# Demo4 - Scripted Model Construction This demo illustrates the usage of sripted model consturction of pyuppaal, constructing the [model](https://github.com/Jack0Chan/pyuppaal/blob/main/src/test_unit/constructed_model1.xml) shown below: ## 1. Setup Pyuppaal ```python import os import pyuppaal from pyuppaal.nta import Template, Location, Edge pyuppaal.set_verifyta_path(r"C:\Users\10262\Documents\GitHub\cav2024\bin\uppaal64-4.1.26\bin-Windows\verifyta.exe") ``` ## 2. Create New Model File with declaration. ```python model_path = 'constructed_model1.xml' os.remove(model_path) umodel = pyuppaal.UModel.new(model_path) umodel.declaration = """// Place global declarations here. broadcast chan a, b, c; int count = 0; int sender_count = 0; const int rec_end = 10;\n""" ``` ## 3. Construct Receiver Template ```python # region: 构建tempaltes,一共两个 # region: 构建第1个template template0 = Template(name="Receiver", locations=[], init_ref=0, edges=[], params="broadcast chan ¶m1, broadcast chan ¶m2, int inv_start, int guard_start", declaration="""// Place local declarations here.\nclock t;""") # 构造locations # l0 是initial location l0 = Location(location_id=0, location_pos=(-391, -102), name="Start", name_pos=(-401, -136), invariant="t<=inv_start", invariant_pos=(-401, -85), test_code_on_enter="count ++;", test_code_on_exit="count = 10;", is_initial=True) l1 = Location(location_id=1, location_pos=(-170, -102), invariant="t<=200", invariant_pos=(-178, -76), rate_of_exponential=0.8, rate_of_exp_pos=(-179, -93)) l2 = Location(location_id=2, location_pos=(-42, -93), is_urgent=True) l3 = Location(location_id=3, location_pos=(-76, -212), is_committed=True) l4 = Location(location_id=4, location_pos=(25, -212), name="End1", name_pos=(15, -246)) l5 = Location(location_id=5, location_pos=(51, -93), name="End2", name_pos=(41, -127), comments="备注End2", comments_pos=(42, -34)) # 构造branch points bp0 = Location(location_id=6, location_pos=(-119, -144), is_branchpoint=True) template0.locations = [l0, l1, l2, l3, l4, l5, bp0] # 构造edges e0 = Edge(source_location_id=2, source_location_pos=(-42, -93), target_location_id=5, target_location_pos=(34, -93), sync="param2?", sync_pos=(-24, -110), update="t=888", update_pos=(-24, -93)) e1 = Edge(source_location_id=3, source_location_pos=(-76, -212), target_location_id=4, target_location_pos=(25, -212), sync="param1?", sync_pos=(-58, -229), update="t=999", update_pos=(-51, -212)) e2 = Edge(source_location_id=6, source_location_pos=(-119, -144), target_location_id=3, target_location_pos=(-76, -212), probability_weight=0.2, prob_weight_pos=(-93, -178)) e3 = Edge(source_location_id=6, source_location_pos=(-119, -144), target_location_id=2, target_location_pos=(-42, -93), probability_weight=0.8, prob_weight_pos=(-93, -119)) e4 = Edge(source_location_id=1, source_location_pos=(-178, -102), target_location_id=6, target_location_pos=(-119, -144)) e5 = Edge(source_location_id=0, source_location_pos=(-391, -102), target_location_id=1, target_location_pos=(-178, -102), guard="t>= guard_start", guard_pos=(-331, -102), update="count ++", update_pos=(-306, -85), test_code="count == -1;") template0.edges = [e0, e1, e2, e3, e4, e5] # template0.branch_points = [bp0] # endregion ``` ## 4. Construct Sender Template ```python # region: 构建第2个template template1 = Template(name="Sender", locations=[], init_ref=7, edges=[], params="broadcast chan ¶m1, broadcast chan ¶m2", declaration=None) # 构造locations l7 = Location(location_id=7, location_pos=(-459, -34), name="Start", name_pos=(-493, -68), test_code_on_enter="sender_count = 10;", test_code_on_exit="sender_count = -1;", comments="""Start:\nTestCode""", comments_pos=(-469, 25), is_initial=True) l8 = Location(location_id=8, location_pos=(-187, -102)) l9 = Location(location_id=9, location_pos=(-178, 17)) # l10 = Location(location_id=10,location_pos=(-323,-34)) # 构造branch points bp1 = Location(location_id=10, location_pos=(-323, -34), is_branchpoint=True) template1.locations = [l7, l8, l9, bp1] # 构造edges e6 = Edge(source_location_id=10, source_location_pos=(-323, -34), target_location_id=9, target_location_pos=(-178, 17), sync="param2!", sync_pos=(-305, -34)) e7 = Edge(source_location_id=10, source_location_pos=(-323, -34), target_location_id=8, target_location_pos=(-187, -102), sync="param1!", sync_pos=(-305, -80), probability_weight=0.8, prob_weight_pos=(-305, -51)) e8 = Edge(source_location_id=7, source_location_pos=(-459, -34), target_location_id=10, target_location_pos=(-323, -34), nails=[(-382, -136)]) template1.edges = [e6, e7, e8] # print(template1.edges) # template1.branch_points = [bp1] # endregion # endregion 构造templates umodel.templates = [template0, template1] ``` ## 5. Set System and Queries ```python umodel.system = """// Place template instantiations here. rec = Receiver(a, b, 10, rec_end); sender = Sender(a, b); // List one or more processes to be composed into a system. system rec, sender;\n""" umodel.queries = ["E<> sender_count == 10", "E<> count == 1", "E<> rec.End1", "E<> rec.t >= 10", "A[] not deadlock"] ``` ## 6. Verify and Easy Verify ```python print("umodel.verify() results: ") print(umodel.verify()) print("umodel.easy_verify().untime_pattern: (easy_verify() will only return the trace of the FIRST query.)") # easy_verify() only aceepts ONE query. tmp_new_model = umodel.copy_as('tmp_new.xml') tmp_new_model.queries = "E<> rec.End1" print(tmp_new_model.queries) st = tmp_new_model.easy_verify(keep_tmp_file=True).raw print(st) # assert last state of st is rec.End1 # os.remove('tmp_new.xml') ``` umodel.verify() results: Writing example trace to constructed_model1-2.xtr Writing example trace to constructed_model1-3.xtr Writing example trace to constructed_model1-4.xtr Writing counter example to constructed_model1-5.xtr Options for the verification: Generating shortest trace Search order is breadth first Using conservative space optimisation Seed is 1713421808 State space representation uses minimal constraint systems  Verifying formula 1 at /nta/queries/query[1]/formula  -- Formula is NOT satisfied.  Verifying formula 2 at /nta/queries/query[2]/formula  -- Formula is satisfied.  Verifying formula 3 at /nta/queries/query[3]/formula  -- Formula is satisfied.  Verifying formula 4 at /nta/queries/query[4]/formula  -- Formula is satisfied.  Verifying formula 5 at /nta/queries/query[5]/formula  -- Formula is NOT satisfied. umodel.easy_verify().untime_pattern: (easy_verify() will only return the trace of the FIRST query.) ['E<> rec.End1'] State: rec.Start sender.Start count=0 sender_count=0 rec.inv_start=10 rec.guard_start=10 t(0)-rec.t<=0 rec.t-t(0)<=10 Transition: rec._id2 -> rec.End2 {1; param2?; t = 888;} State: rec._id1 sender.Start count=1 sender_count=0 rec.inv_start=10 rec.guard_start=10 t(0)-rec.t<=-10 rec.t-t(0)<=200 Transition: rec._id1 -> rec._id3 {1; 0; 1, 1;} rec.Start -> rec._id1 {t >= guard_start; 0; count++;} ## 7. Check Correctness ```python target_model = pyuppaal.UModel("test_umodel_build.xml") assert "E<> sender_count == 10" == umodel.queries[0] assert umodel.queries == target_model.queries assert umodel.system == target_model.system assert umodel.declaration == target_model.declaration assert umodel.templates[0].xml == target_model.templates[0].xml assert umodel.templates[1].xml == target_model.templates[1].xml assert umodel.xml == target_model.xml assert "Verifying formula" in umodel.verify() ```